<template>
  <div class="hello">
    <div>
      类名:
      <input type="text" @change="setClassName($event)" />
      属性:
      <input type="text" @change="setAttrName($event)" />
      方法:
      <input type="text" @change="setfuncName($event)" />
      选择连线样式:
      <select name="edgeSelect" @change="selectFn($event)">
        <option value="polyline">折线</option>
        <option value="line">直线</option>
        <option value="quadratic">二阶贝塞尔曲线</option>
        <option value="cubic">三阶贝塞尔曲线</option>
      </select>
      选择布局:
      <select name="layoutSelect" @change="selectlayout($event)">
        <option value="TB">根节点在上，往下布局</option>
        <option value="BT">根节点在下，往上布局</option>
        <option value="LR">根节点在左，往右布局</option>
        <option value="RL">根节点在右，往左布局</option>
        <option value="H">根节点在中间，水平对称布局</option>
        <option value="V">根节点在中间，垂直对称布局</option>
      </select>
    </div>
    <div class="custom-tree-container">
      <!-- <div class="block">
        <p>使用 render-content</p>
        <el-tree
          :data="treedata"
          show-checkbox
          node-key="id"
          default-expand-all
          :expand-on-click-node="false"
          :render-content="renderContent"
        ></el-tree>
      </div> -->
      <div class="block">
        <p>使用 scoped slot</p>
        <el-tree
          :data="treedata"
          show-checkbox
          node-key="id"
          default-expand-all
          :expand-on-click-node="false"
        >
          <span class="custom-tree-node" slot-scope="{ node, data }">
            <span>{{ node.label }}</span>
            <span>
              <el-button type="text" size="mini" @click="() => append(data)">Append</el-button>
              <el-button type="text" size="mini" @click="() => remove(node, data)">Delete</el-button>
            </span>
          </span>
        </el-tree>
      </div>
    </div>
    <div
      id="mountNode"
      style="width:1500px; height:800px;border: 2px;border-color: #53534b;border-style: solid;"
    ></div>
  </div>
</template>

<script>
import G6 from "@antv/g6";
let id = 1000;
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    const treedata = [
      {
        id: 1,
        label: "一级 1",
        children: [
          {
            id: 4,
            label: "二级 1-1",
            children: [
              {
                id: 9,
                label: "三级 1-1-1"
              },
              {
                id: 10,
                label: "三级 1-1-2"
              }
            ]
          }
        ]
      },
      {
        id: 2,
        label: "一级 2",
        children: [
          {
            id: 5,
            label: "二级 2-1"
          },
          {
            id: 6,
            label: "二级 2-2"
          }
        ]
      },
      {
        id: 3,
        label: "一级 3",
        children: [
          {
            id: 7,
            label: "二级 3-1"
          },
          {
            id: 8,
            label: "二级 3-2"
          }
        ]
      }
    ];
    return {
      data: {
        /* classAName:"ClassA",
        classAattr:'attrA',
        classAfunc:'funcA', */
        graph: null,
        nodes: [
          {
            id: "node1",
            x: 350,
            y: 300,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          {
            id: "node2",
            x: 750,
            y: 100,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          //{ id: "node3", x: 50, y: 170, size: [50, 50] },
          {
            id: "node4",
            x: 750,
            y: 170,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          //{ id: "node5", x: 50, y: 240, size: [50, 50] },
          {
            id: "node6",
            x: 750,
            y: 240,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          //{ id: "node7", x: 50, y: 310, size: [50, 50] },
          {
            id: "node8",
            x: 750,
            y: 310,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          //{ id: "node9", x: 50, y: 380, size: [50, 50] },
          {
            id: "node10",
            x: 750,
            y: 380,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          },
          //{ id: "node11", x: 50, y: 450, size: [50, 50] },
          {
            id: "node12",
            x: 750,
            y: 450,
            size: [50, 50],
            className: "ClassA",
            attrName: "attrA",
            funcName: "funcA"
          }
        ],
        edges: [
          {
            source: "node1",
            target: "node2",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 0,0 L 15,5 L 15,-5 Z",
                fill: "#fff"
              }
            },
            label: "继承(Inheritance)",
            labelCfg: {
              refY: 10,
              refX: -20,
              position: "end",
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          },
          {
            source: "node1",
            target: "node4",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 15,5 L 0,0 L 15,-5 "
              }
            },
            label: "关联(Aggregation)",
            labelCfg: {
              position: "end",
              refX: -20,
              refY: 10,
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          },
          {
            source: "node1",
            target: "node6",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              lineDash: [5, 5],
              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 0,0 L 15,5 L 15,-5 Z",
                fill: "#fff",
                lineDash: [0, 0]
              }
            },
            label: "实现(Implementation)",
            labelCfg: {
              position: "end",
              refY: 10,
              refX: -20,
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          },
          {
            source: "node1",
            target: "node8",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              lineDash: [5, 5],

              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 15,5 L 0,0 L 15,-5 ",
                lineDash: [0, 0]
              }
            },
            label: "依赖(Dependency)",
            labelCfg: {
              position: "end",
              refX: -20,
              refY: 10,
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          },
          {
            source: "node1",
            target: "node10",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 0,0 L 15,5 L 30,0 L 15,-5 Z",
                fill: "#fff"
              }
            },
            label: "聚合(Aggregation)",
            labelCfg: {
              position: "end",
              refX: -20,
              refY: 10,
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          },
          {
            source: "node1",
            target: "node12",
            style: {
              lineWidth: 2,
              stroke: "#000000",
              endArrow: {
                // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                path: "M 0,0 L 15,5 L 30,0 L 15,-5 Z",
                fill: "#000"
              }
            },
            label: "复合(Composition)",
            labelCfg: {
              position: "end",
              refX: -20,
              refY: 10,
              style: {
                stroke: "white", // 给文本添加白边和白色背景
                lineWidth: 5, // 文本白边粗细
                fill: "#722ed1" // 文本颜色
              }
            }
          }
        ]
      },
      treedata: JSON.parse(JSON.stringify(treedata))
      
    };
  },

  methods: {
    selectFn(e) {
      console.log(e);
      console.log(e.target.selectedIndex); // 选择项的index索引
      console.log(e.target.value); // 选择项的value
      for (var xx of this.data.edges) {
        xx.type = e.target.value;
      }
      this.graph.render();
    },
    selectlayout(e) {
      console.log(e);
      this.graph.layout = {
        type: "dendrogram", // 布局名称
        direction: e.target.value, // 自左至右布局，可选的有 H / V / LR / RL / TB / BT
        nodeSep: 50, // 节点之间间距
        rankSep: 100 // 每个层级之间的间距
      };
    },
    setClassName(e) {
      this.data.nodes[0].className = "类名：" + e.target.value;
      this.graph.render();
    },
    setAttrName(e) {
      this.data.nodes[0].attrName = "属性：" + e.target.value;
      this.graph.render();
    },
    setfuncName(e) {
      this.data.nodes[0].funcName = "方法：" + e.target.value;
      this.graph.render();
    },
    append(data) {
      const newChild = { id: id++, label: "testtest", children: [] };
      if (!data.children) {
        this.$set(data, "children", []);
      }
      data.children.push(newChild);
    },
    remove(node, data) {
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex(d => d.id === data.id);
      children.splice(index, 1);
    },
    renderContent(h, { node, data, store }) {
      return (
        <span class="custom-tree-node">
          <span>{node.label}</span>
          <span>
            <el-button
              size="mini"
              type="text"
              on-click={() => this.append(data)}
            >
              Append
            </el-button>
            <el-button
              size="mini"
              type="text"
              on-click={() => this.remove(node, data)}
            >
              Delete
            </el-button>
          </span>
        </span>
      );
    }
  },
  mounted() {
    G6.registerNode("UML-node", {
      draw(cfg, group) {
        let width = 0;
        let height = 0;
        const classNameText = group.addShape("text", {
          attrs: {
            text: cfg.className,
            x: -width / 2 + 2,
            y: -height / 2 + 2,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0)"
          },
          name: "class-name",
          draggable: true
        });
        const classNameBox = classNameText.getBBox();
        const attrNameText = group.addShape("text", {
          attrs: {
            text: cfg.attrName,
            x: -width / 2 + 2,
            y: -height / 2 + 4 + classNameBox.height,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0)"
          },
          name: "attr-name",
          draggable: true
        });
        const attrNameBox = attrNameText.getBBox();
        const funcNameText = group.addShape("text", {
          attrs: {
            text: cfg.funcName,
            x: -width / 2 + 2,
            y: -height / 2 + 6 + classNameBox.height + attrNameBox.height,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0)"
          },
          name: "func-name",
          draggable: true
        });
        const funcNameBox = funcNameText.getBBox();

        let max1 =
          classNameBox.width > attrNameBox.width
            ? classNameBox.width
            : attrNameBox.width;
        let max2 = max1 > funcNameBox.width ? max1 : funcNameBox.width;
        const size1 = [
          max2 + 4,
          classNameBox.height + attrNameBox.height + funcNameBox.height + 8
        ];
        width = size1[0];
        height = size1[1];
        // 如果 cfg 中定义了 style 需要同这里的属性进行融合
        const keyShape = group.addShape("path", {
          attrs: {
            path: this.getPath(size1), // 根据配置获取路径
            stroke: cfg.color || "#000", // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            fill: cfg.color || "#E0EEEE" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: "path-shape",
          // 设置 draggable 以允许响应鼠标的图拽事件
          draggable: true
        });

        group.addShape("text", {
          attrs: {
            text: cfg.className,
            x: -width / 2 + 2,
            y: -height / 2 + 2,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0.65)"
          },
          name: "class-name",
          draggable: true
        });

        group.addShape("path", {
          attrs: {
            path: [
              ["M", -width / 2, -height / 2 + classNameBox.height + 2],
              ["L", width / 2, -height / 2 + classNameBox.height + 2]
            ],
            stroke: cfg.color || "#000", // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            fill: cfg.color || "#E0EEEE" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            //lineWidth: 8
          },
          name: "111",
          draggable: true
        });

        group.addShape("text", {
          attrs: {
            text: cfg.attrName,
            x: -width / 2 + 2,
            y: -height / 2 + 4 + classNameBox.height,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0.65)"
          },
          name: "attr-name",
          draggable: true
        });

        group.addShape("path", {
          attrs: {
            path: [
              [
                "M",
                -width / 2,
                -height / 2 + classNameBox.height + attrNameBox.height + 4
              ],
              [
                "L",
                width / 2,
                -height / 2 + classNameBox.height + attrNameBox.height + 4
              ]
            ],
            stroke: cfg.color || "#000", // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            fill: cfg.color || "#E0EEEE" // 颜色应用到描边上，如果应用到填充，则使用 fill: cfg.color
            //lineWidth: 8
          },
          name: "111",
          draggable: true
        });
        group.addShape("text", {
          attrs: {
            text: cfg.funcName,
            x: -width / 2 + 2,
            y: -height / 2 + 6 + classNameBox.height + attrNameBox.height,
            fontSize: 12,
            textAlign: "left",
            textBaseline: "top",
            fill: "rgba(0,0,0,0.65)"
          },
          name: "func-name",
          draggable: true
        });
        if (cfg.label) {
          // 如果有文本
          // 如果需要复杂的文本配置项，可以通过 labeCfg 传入
          // const style = (cfg.labelCfg && cfg.labelCfg.style) || {};
          // style.text = cfg.label;
          const label = group.addShape("text", {
            // attrs: style
            attrs: {
              x: 0, // 居中
              y: 0,
              textAlign: "center",
              textBaseline: "middle",
              text: cfg.label,
              fill: "#666"
            },
            // must be assigned in G6 3.3 and later versions. it can be any value you want
            name: "text-shape",
            // 设置 draggable 以允许响应鼠标的图拽事件
            draggable: true
          });
        }
        return keyShape;
      },
      // 返回菱形的路径
      getPath(size1) {
        const size = size1 || [40, 40]; // 如果没有 size 时的默认大小
        const width = size[0];
        const height = size[1];
        //  / 1 \
        // 4     2
        //  \ 3 /
        const path = [
          ["M", -width / 2, 0 - height / 2], // 上部顶点
          ["L", width / 2, -height / 2], // 右侧顶点
          ["L", width / 2, height / 2], // 下部顶点
          ["L", -width / 2, height / 2], // 左侧顶点
          ["Z"] // 封闭
        ];
        return path;
      }
    });

    this.graph = new G6.Graph({
      container: "mountNode",
      width: 1500,
      height: 800,
      defaultNode: {
        type: "UML-node"
        //type :'rect'
        // 其他配置
      },
      modes: {
        default: ["drag-canvas", "zoom-canvas", "drag-node"], // 允许拖拽画布、放缩画布、拖拽节点
        edit: ["click-select"]
      },
      defaultEdge: {
        type: "polyline",
        style: {
          lineWidth: 2,
          stroke: "#000000",
          endArrow: true
        }
        // 其他配置
      }
      // 定义布局
    });

    this.graph.data(this.data);
    this.graph.render();
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
